# -*- coding: utf-8 -*-
"""
天翼云盘适配器
@api-version: 1.0.0
// REF: API-NETDISK-008
"""

import requests
import hashlib
import time
import json
from datetime import datetime, timedelta
from typing import Dict, Any, BinaryIO
from urllib.parse import urlencode

from .base import CloudStorageAdapter

class TianyiCloudAdapter(CloudStorageAdapter):
    """天翼云盘适配器
    
    实现天翼云盘的文件上传、下载、删除等操作
    支持OAuth2.0认证和API调用
    """
    
    # 天翼云盘API端点
    BASE_URL = 'https://api.cloud.189.cn'
    AUTH_URL = 'https://oauth.api.189.cn'
    UPLOAD_URL = 'https://upload.api.cloud.189.cn'
    
    def __init__(self, app_id: str, app_secret: str, access_token: str = None, 
                 refresh_token: str = None, **kwargs):
        """初始化天翼云盘适配器
        
        Args:
            app_id: 应用ID
            app_secret: 应用密钥
            access_token: 访问令牌
            refresh_token: 刷新令牌
        """
        super().__init__(**kwargs)
        
        self.app_id = app_id
        self.app_secret = app_secret
        self.access_token = access_token
        self.refresh_token = refresh_token
        self.token_expires_at = None
        
        # 请求会话
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'SnailClouds/1.0.0',
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        })
    
    def _ensure_valid_token(self):
        """确保访问令牌有效"""
        if not self.access_token:
            raise ValueError("Access token is required")
        
        # 检查令牌是否即将过期（提前5分钟刷新）
        if (self.token_expires_at and 
            datetime.utcnow() + timedelta(minutes=5) >= self.token_expires_at):
            self._refresh_access_token()
    
    def _refresh_access_token(self):
        """刷新访问令牌"""
        if not self.refresh_token:
            raise ValueError("Refresh token is required")
        
        url = f"{self.AUTH_URL}/oauth2/access_token"
        data = {
            'grant_type': 'refresh_token',
            'refresh_token': self.refresh_token,
            'client_id': self.app_id,
            'client_secret': self.app_secret
        }
        
        try:
            response = self.session.post(url, data=data)
            response.raise_for_status()
            
            token_data = response.json()
            self.access_token = token_data['access_token']
            self.refresh_token = token_data.get('refresh_token', self.refresh_token)
            
            # 计算令牌过期时间
            expires_in = token_data.get('expires_in', 3600)
            self.token_expires_at = datetime.utcnow() + timedelta(seconds=expires_in)
            
        except Exception as e:
            raise Exception(f"Failed to refresh access token: {e}")
    
    def _make_api_request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
        """发起API请求
        
        Args:
            method: HTTP方法
            endpoint: API端点
            **kwargs: 请求参数
        
        Returns:
            Dict: API响应
        """
        self._ensure_valid_token()
        
        url = f"{self.BASE_URL}{endpoint}"
        headers = kwargs.pop('headers', {})
        headers['Authorization'] = f'Bearer {self.access_token}'
        
        try:
            response = self.session.request(method, url, headers=headers, **kwargs)
            response.raise_for_status()
            
            # 处理空响应
            if not response.content:
                return {'success': True}
            
            return response.json()
            
        except requests.exceptions.RequestException as e:
            return {
                'success': False,
                'error_code': getattr(e.response, 'status_code', 0),
                'error_message': str(e)
            }
        except json.JSONDecodeError as e:
            return {
                'success': False,
                'error_message': f'Invalid JSON response: {e}'
            }
    
    def upload_file(self, file_stream: BinaryIO, file_name: str, 
                   file_size: int, content_type: str = None) -> Dict[str, Any]:
        """上传文件到天翼云盘"""
        try:
            # 1. 获取上传地址
            upload_info = self._get_upload_url(file_name, file_size)
            if not upload_info.get('success'):
                return upload_info
            
            upload_url = upload_info['upload_url']
            upload_token = upload_info['upload_token']
            
            # 2. 上传文件
            file_stream.seek(0)
            files = {
                'file': (file_name, file_stream, content_type or 'application/octet-stream')
            }
            
            data = {
                'token': upload_token,
                'fileName': file_name,
                'fileSize': file_size
            }
            
            response = requests.post(upload_url, files=files, data=data)
            response.raise_for_status()
            
            result = response.json()
            
            if result.get('code') == 0:  # 天翼云盘成功码
                cloud_file_id = result['data']['fileId']
                
                # 3. 获取下载链接
                download_info = self.get_download_url(cloud_file_id)
                
                return self._format_success_response(
                    cloud_file_id=cloud_file_id,
                    download_url=download_info.get('download_url', ''),
                    expires_at=download_info.get('expires_at'),
                    file_size=file_size
                )
            else:
                return self._format_error_response(
                    f"Upload failed: {result.get('message', 'Unknown error')}"
                )
                
        except Exception as e:
            return self._format_error_response(f"Upload error: {e}")
    
    def _get_upload_url(self, file_name: str, file_size: int) -> Dict[str, Any]:
        """获取上传地址和令牌"""
        endpoint = '/open/file/getUploadUrl'
        data = {
            'fileName': file_name,
            'fileSize': file_size,
            'md5': '',  # 可选的MD5校验
            'parentId': 0  # 根目录
        }
        
        result = self._make_api_request('POST', endpoint, json=data)
        
        if result.get('code') == 0:
            upload_data = result['data']
            return self._format_success_response(
                upload_url=upload_data['uploadUrl'],
                upload_token=upload_data['uploadToken']
            )
        else:
            return self._format_error_response(
                f"Failed to get upload URL: {result.get('message', 'Unknown error')}"
            )
    
    def get_download_url(self, cloud_file_id: str, expires_in: int = 3600) -> Dict[str, Any]:
        """获取文件下载链接"""
        endpoint = f'/open/file/getDownloadUrl'
        params = {
            'fileId': cloud_file_id,
            'dt': 3,  # 下载类型：3=直链下载
            'expires': expires_in
        }
        
        result = self._make_api_request('GET', endpoint, params=params)
        
        if result.get('code') == 0:
            download_url = result['data']['downloadUrl']
            expires_at = self._calculate_expires_at(expires_in)
            
            return self._format_success_response(
                download_url=download_url,
                expires_at=expires_at
            )
        else:
            return self._format_error_response(
                f"Failed to get download URL: {result.get('message', 'Unknown error')}"
            )
    
    def delete_file(self, cloud_file_id: str) -> Dict[str, Any]:
        """删除云端文件"""
        endpoint = '/open/file/deleteFile'
        data = {
            'fileId': cloud_file_id
        }
        
        result = self._make_api_request('POST', endpoint, json=data)
        
        if result.get('code') == 0:
            return self._format_success_response()
        else:
            return self._format_error_response(
                f"Failed to delete file: {result.get('message', 'Unknown error')}"
            )
    
    def get_file_info(self, cloud_file_id: str) -> Dict[str, Any]:
        """获取文件信息"""
        endpoint = '/open/file/getFileInfo'
        params = {
            'fileId': cloud_file_id
        }
        
        result = self._make_api_request('GET', endpoint, params=params)
        
        if result.get('code') == 0:
            file_data = result['data']
            
            return self._format_success_response(
                file_id=file_data['fileId'],
                file_name=file_data['fileName'],
                file_size=file_data['fileSize'],
                content_type=file_data.get('contentType', ''),
                created_at=self._parse_timestamp(file_data.get('createTime')),
                modified_at=self._parse_timestamp(file_data.get('lastOpTime'))
            )
        else:
            return self._format_error_response(
                f"Failed to get file info: {result.get('message', 'Unknown error')}"
            )
    
    def get_storage_quota(self) -> Dict[str, Any]:
        """获取存储配额信息"""
        endpoint = '/open/user/getUserInfo'
        
        result = self._make_api_request('GET', endpoint)
        
        if result.get('code') == 0:
            user_data = result['data']
            quota_data = user_data.get('quota', {})
            
            total_space = quota_data.get('totalSpace', 0)
            used_space = quota_data.get('usedSpace', 0)
            available_space = total_space - used_space
            
            return self._format_success_response(
                total_space=total_space,
                used_space=used_space,
                available_space=max(0, available_space)
            )
        else:
            return self._format_error_response(
                f"Failed to get storage quota: {result.get('message', 'Unknown error')}"
            )
    
    def batch_delete_files(self, cloud_file_ids: list) -> Dict[str, Any]:
        """批量删除文件"""
        endpoint = '/open/file/batchDeleteFile'
        data = {
            'fileIds': cloud_file_ids
        }
        
        result = self._make_api_request('POST', endpoint, json=data)
        
        if result.get('code') == 0:
            success_count = result['data'].get('successCount', 0)
            failed_files = result['data'].get('failedFiles', [])
            
            return self._format_success_response(
                deleted_count=success_count,
                failed_files=failed_files
            )
        else:
            return self._format_error_response(
                f"Batch delete failed: {result.get('message', 'Unknown error')}"
            )
    
    def test_connection(self) -> Dict[str, Any]:
        """测试连接"""
        start_time = time.time()
        
        try:
            result = self.get_storage_quota()
            response_time = time.time() - start_time
            
            if result.get('success'):
                return self._format_success_response(
                    response_time=response_time
                )
            else:
                return self._format_error_response(
                    result.get('error_message', 'Connection test failed'),
                    response_time=response_time
                )
                
        except Exception as e:
            response_time = time.time() - start_time
            return self._format_error_response(
                f"Connection test error: {e}",
                response_time=response_time
            )
    
    def generate_upload_token(self, file_name: str, file_size: int) -> Dict[str, Any]:
        """生成上传令牌（用于客户端直传）"""
        try:
            upload_info = self._get_upload_url(file_name, file_size)
            
            if upload_info.get('success'):
                return self._format_success_response(
                    upload_token=upload_info['upload_token'],
                    upload_url=upload_info['upload_url'],
                    expires_at=self._calculate_expires_at(3600)  # 1小时有效期
                )
            else:
                return upload_info
                
        except Exception as e:
            return self._format_error_response(f"Failed to generate upload token: {e}")
    
    def _parse_timestamp(self, timestamp_str: str) -> datetime:
        """解析时间戳字符串"""
        if not timestamp_str:
            return None
        
        try:
            # 天翼云盘时间戳格式：2023-12-01 12:00:00
            return datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
        except ValueError:
            try:
                # 尝试Unix时间戳
                return datetime.fromtimestamp(int(timestamp_str) / 1000)
            except (ValueError, TypeError):
                return None
    
    def _generate_signature(self, params: Dict[str, Any]) -> str:
        """生成API签名（如果需要）"""
        # 按键名排序
        sorted_params = sorted(params.items())
        
        # 构建签名字符串
        sign_str = '&'.join([f'{k}={v}' for k, v in sorted_params])
        sign_str += f'&app_secret={self.app_secret}'
        
        # MD5签名
        return hashlib.md5(sign_str.encode('utf-8')).hexdigest()
    
    def get_supported_features(self) -> Dict[str, bool]:
        """获取天翼云盘支持的功能"""
        return {
            'upload': True,
            'download': True,
            'delete': True,
            'file_info': True,
            'batch_delete': True,
            'direct_upload': True,
            'storage_quota': True,
            'connection_test': True
        }
    
    def __str__(self):
        return f"TianyiCloudAdapter(app_id={self.app_id})"